#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_timer.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_interface.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_commands.h"

#include "logo_en_240x240_lcd.h"

#include "esp_lcd_touch.h"
#include "esp_lcd_touch_cst816s.h"

//#include "driver/i2c.h"
#include "driver/i2c_master.h"
#include "demos/lv_demos.h"
#include "esp_lvgl_port.h"
#include "lvgl.h"


#define LCD_PIN_BLK     GPIO_NUM_42
#define LCD_PIN_CS      GPIO_NUM_10
#define LCD_PIN_DC      GPIO_NUM_39
#define LCD_PIN_MOSI    GPIO_NUM_40
#define LCD_PIN_SCK     GPIO_NUM_41
#define LCD_PIN_REST      GPIO_NUM_9
    

#define LCD_SPI_HOST    SPI3_HOST

#define RED   0x00F8  // 红色 RGB565
#define GREEN 0x07E0    // 绿色 RGB565
#define BLUE  0x001F  // 蓝色 RGB565

#define LCD_V_RES   280
#define LCD_H_RES   240

#define EXAMPLE_ST7789_TAG "EXAMPLE_ST7789_TAG"

static esp_lcd_panel_io_handle_t io_handle = NULL;
static esp_lcd_panel_handle_t panel_handle = NULL;
static esp_lcd_touch_handle_t touchpad_handle;
void example_lcd_set_color(uint16_t color);
void lcd_draw_pictrue(int x_start, int y_start, int x_end, int y_end, const unsigned char *gImage);

void example_lcd_init(){
    ESP_LOGI(EXAMPLE_ST7789_TAG, "Turn off LCD backlight");
    gpio_config_t bk_gpio_config = {
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = 1ULL << LCD_PIN_BLK
    };
    ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));

    ESP_LOGI(EXAMPLE_ST7789_TAG, "Initialize SPI bus");
    spi_bus_config_t buscfg = {
        .sclk_io_num = LCD_PIN_SCK,
        .mosi_io_num = LCD_PIN_MOSI,
        .miso_io_num = -1,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = LCD_V_RES * LCD_H_RES * sizeof(uint16_t),
    };
    ESP_ERROR_CHECK(spi_bus_initialize(LCD_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));

    ESP_LOGI(EXAMPLE_ST7789_TAG, "Install panel IO");
    
    esp_lcd_panel_io_spi_config_t io_config = {
        .dc_gpio_num = LCD_PIN_DC,
        .cs_gpio_num = LCD_PIN_CS,
        .pclk_hz = (80 * 1000 * 1000),
        .lcd_cmd_bits = 8,
        .lcd_param_bits = 8,
        .spi_mode = 2,
        .trans_queue_depth = 10
    };
    // Attach the LCD to the SPI bus
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_SPI_HOST, &io_config, &io_handle));

    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = LCD_PIN_REST,    // 连接 LCD 复位信号的 IO 编号，可以设为 `-1` 表示不使用
        .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,   // 像素色彩的元素顺序（RGB/BGR），
                                                    //  一般通过命令 `LCD_CMD_MADCTL（36h）` 控制
        .bits_per_pixel = 16,  // 色彩格式的位数（RGB565：16，RGB666：18），
    };


    ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));

    ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
    //esp_lcd_panel_io_tx_param(panel_handle,LCD_CMD_COLMOD,(uint8_t[]) {0x55,}, 1);  
    esp_lcd_panel_invert_color(panel_handle, true); // 颜色反转
    //esp_lcd_panel_swap_xy(panel_handle, true);  // 显示翻转 
    //ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, true, false));

    // user can flush pre-defined pattern to the screen before we turn on the screen or backlight
    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));

    ESP_LOGI(EXAMPLE_ST7789_TAG, "Turn on LCD backlight");
    gpio_set_level(LCD_PIN_BLK, true);

    // 设置一个16位的颜色值
    example_lcd_set_color(RED);
}






extern esp_err_t bsp_i2c_init();


esp_lcd_panel_io_handle_t tp_io_handle = NULL;
extern i2c_master_bus_handle_t bsp_i2c_bus;
void example_cst816_init(){

    bsp_i2c_init();
     
    esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG();

   
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c_v2(bsp_i2c_bus, &tp_io_config, &tp_io_handle));

    esp_lcd_touch_config_t tp_cfg = {
        .x_max = LCD_H_RES,
        .y_max = LCD_V_RES,
        .rst_gpio_num = GPIO_NUM_NC,
        .int_gpio_num = GPIO_NUM_NC,
        .levels = {
            .reset = 0,
            .interrupt = 0,
        },
        .flags = {
            .swap_xy = 0,
            .mirror_x = 0,
            .mirror_y = 0,
        }
    };

    esp_lcd_touch_new_i2c_cst816s(tp_io_handle, &tp_cfg, &touchpad_handle);
}


void example_st7789_lvgl_test(){
    // 初始化显示屏幕
    example_lcd_init();
    
    // 初始化触摸
    example_cst816_init();

    lvgl_port_cfg_t port_config = ESP_LVGL_PORT_INIT_CONFIG();
    lvgl_port_init(&port_config);

    // 显示部分初始化
    const lvgl_port_display_cfg_t disp_cfg = {
        .io_handle = io_handle,
        .panel_handle = panel_handle,
        .buffer_size = LCD_H_RES*50*sizeof(uint16_t),
        .double_buffer = true,
        .hres = LCD_H_RES,
        .vres = LCD_V_RES,
        .monochrome = false,
        /* Rotation values must be same as used in esp_lcd for initial settings of the screen */
        .rotation = {
            .swap_xy = false,
            .mirror_x = false,
            .mirror_y = false,
        },
        .flags = {
            .buff_dma = true,
            .buff_spiram = false,
        }
    };

    lv_display_t *disp = lvgl_port_add_disp(&disp_cfg);

    esp_lcd_panel_set_gap(panel_handle,0,20);

    //////////////////////////////////触摸部分初始化//////////////////////////////////////
    const lvgl_port_touch_cfg_t touch_cfg = {
        .disp = disp,
        .handle = touchpad_handle,
    };

    lvgl_port_add_touch(&touch_cfg);

    lvgl_port_lock(-1);

    lv_demo_widgets();
    
    lvgl_port_unlock();
    //lv_demo_benchmark();

}




// 显示图片
void lcd_draw_pictrue(int x_start, int y_start, int x_end, int y_end, const unsigned char *gImage)
{
    // 分配内存 分配了需要的字节大小 且指定在外部SPIRAM中分配
    size_t pixels_byte_size = (x_end - x_start)*(y_end - y_start) * 2;
    uint16_t *pixels = (uint16_t *)heap_caps_malloc(pixels_byte_size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
    if (NULL == pixels)
    {
        //ESP_LOGE(TAG, "Memory for bitmap is not enough");
        return;
    }
    //memcpy(pixels, gImage, pixels_byte_size);  // 把图片数据拷贝到内存
    esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_end, y_end, (uint16_t *)gImage); // 显示整张图片数据
    heap_caps_free(pixels);  // 释放内存
}


void example_lcd_set_color(uint16_t color)
{
    uint16_t *framebuffer = malloc(LCD_V_RES * LCD_H_RES * sizeof(uint16_t));
    if (framebuffer == NULL) {
        //ESP_LOGE(TAG, "Failed to allocate memory for framebuffer");
        return;
    }

    // 填充缓冲区
    for (int i = 0; i < LCD_V_RES * LCD_H_RES; i++) {
        framebuffer[i] = color;
    }

    // 绘制纯色背景
    esp_lcd_panel_draw_bitmap(panel_handle, 0, 0+20, 240, 280+20, framebuffer);

    // 释放缓冲区
    free(framebuffer);
}